package com.luxoft.scoremanager.server.service.impl;

import com.luxoft.scoremanager.server.dao.ComponentDao;
import com.luxoft.scoremanager.server.dao.ComponentValueDao;
import com.luxoft.scoremanager.server.dao.ScorePackageDao;
import com.luxoft.scoremanager.server.dao.StaticDataDao;
import com.luxoft.scoremanager.server.model.bean.ComponentBean;
import com.luxoft.scoremanager.server.model.bean.ScorePackageBean;
import com.luxoft.scoremanager.server.model.bean.StaticDataBean;
import com.luxoft.scoremanager.server.model.entity.ComponentValue;
import com.luxoft.scoremanager.server.model.entity.ScorePackage;
import com.luxoft.scoremanager.server.model.entity.StaticData;
import com.luxoft.scoremanager.server.service.PackageManagerService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * @author: ANikulin
 */
public class BasicPackageManagerService implements PackageManagerService {

    private final ComponentDao componentDao;

    private final ScorePackageDao scorePackageDao;

    private final StaticDataDao staticDataDao;

    private final ComponentValueDao componentValuesDao;

    public BasicPackageManagerService(ComponentDao componentDao, ScorePackageDao scorePackageDao, StaticDataDao staticDataDao, ComponentValueDao componentValuesDao) {
        this.componentDao = componentDao;
        this.scorePackageDao = scorePackageDao;
        this.staticDataDao = staticDataDao;
        this.componentValuesDao = componentValuesDao;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void addComponentToScorePackageByPackageId(Integer id, ComponentBean componentBean) {
        checkArgument(id != null, "id should be provided");
        checkArgument(componentBean != null, "component should be provided");

        ComponentValue componentValue = new ComponentValue(componentBean);
        //id is checked
        //noinspection ConstantConditions
        componentValue.setScorePackage(scorePackageDao.getById(id));
        componentValuesDao.addComponentValues(componentValue);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void deleteComponentFromScorePackageByPackageId(Integer id, ComponentBean componentBean) {
        checkArgument(id != null, "id should be provided");
        checkArgument(componentBean != null, "component should be provided");
        //this is null checking method
        //noinspection ConstantConditions
        checkArgument(componentBean.getId() != null, "component id should be provided");
        ComponentValue componentValue = new ComponentValue(componentBean);
        //id is checked
        //noinspection ConstantConditions
        componentValue.setScorePackage(scorePackageDao.getById(id));
        componentValuesDao.deleteComponentValues(componentValue);

    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void updateComponentListInScorePackageByPackageId(Integer id, List<ComponentBean> componentBeanList) {
        checkArgument(componentBeanList != null, "component should be provided");
        //argument is checked
        //noinspection ConstantConditions
        for (ComponentBean componentBean : componentBeanList) {
            checkArgument(componentBean != null, "component should be provided");
            //this is null checking method
            //noinspection ConstantConditions
            checkArgument(componentBean.getId() != null, "component id should be provided");
            ComponentValue componentValue = new ComponentValue(componentBean);
            componentValue.setScorePackage(scorePackageDao.getById(id));
            componentValuesDao.updateComponentValues(componentValue);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void updateComponentInScorePackageByPackageId(Integer id, ComponentBean componentBean) {
        checkArgument(componentBean != null, "component should be provided");
        //this is null checking method
        //noinspection ConstantConditions
        checkArgument(componentBean.getId() != null, "component id should be provided");
        ComponentValue componentValue = new ComponentValue(componentBean);
        componentValue.setScorePackage(scorePackageDao.getById(id));
        componentValuesDao.updateComponentValues(componentValue);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public void updateScorePackage(ScorePackageBean scorePackageBean) {
        checkArgument(scorePackageBean != null, "score package should be provided");
        //this is null checking method
        //noinspection ConstantConditions
        checkArgument(scorePackageBean.getId() != null, "score package id should be provided");
        //argument is checked
        //noinspection ConstantConditions
        ScorePackage scorePackage = scorePackageDao.getById(scorePackageBean.getId());
        scorePackage.setStage(scorePackageBean.getStage());
        scorePackageDao.updatePackage(scorePackage);
        if (scorePackageBean.getComponents().size() > 1) {
            this.updateComponentListInScorePackageByPackageId(scorePackageBean.getId(), scorePackageBean.getComponents());
        } else if (scorePackageBean.getComponents().size() == 1) {
            this.updateComponentInScorePackageByPackageId(scorePackageBean.getId(), scorePackageBean.getComponents().get(0));
        }
    }

    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
    @Override
    public ScorePackageBean getScorePackageById(Integer id) {
        checkArgument(id != null, "id should be provided");
        //argument is checked
        //noinspection ConstantConditions
        ScorePackage scorePackage = scorePackageDao.getById(id);
        List<StaticData> staticDataList = staticDataDao.getAll();
        return new ScorePackageBean(scorePackage, staticDataList);
    }

    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
    @Override
    public List<ComponentBean> getAllComponentByIdOfScorePackage(Integer id) {
        checkArgument(id != null, "id should be provided");
        //argument is checked
        //noinspection ConstantConditions
        List<ComponentValue> componentValueList = componentValuesDao.getAllForPackage(id);
        List<ComponentBean> componentBeanList = new ArrayList<ComponentBean>();
        for (ComponentValue componentValue : componentValueList) {
            componentBeanList.add(new ComponentBean(componentValue));
        }
        return componentBeanList;
    }

    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
    @Override
    public List<ComponentBean> getAllComponentByScorePackage(ScorePackageBean scorePackageBean) {
        checkArgument(scorePackageBean != null, "score package should be provided");
        //this is null checking method
        //noinspection ConstantConditions
        checkArgument(scorePackageBean.getId() != null, "score package id should be provided");
        //argument is checked
        //noinspection ConstantConditions
        List<ComponentValue> componentValueList = componentValuesDao.getAllForPackage(scorePackageBean.getId());
        List<ComponentBean> componentBeanList = new ArrayList<ComponentBean>();
        for (ComponentValue componentValue : componentValueList) {
            componentBeanList.add(new ComponentBean(componentValue));
        }
        return componentBeanList;
    }

    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
    @Override
    public List<StaticDataBean> getAllStaticData() {
        List<StaticData> staticDataList = staticDataDao.getAll();
        List<StaticDataBean> staticDataBeanList = new ArrayList<StaticDataBean>();
        for (StaticData staticData : staticDataList) {
            staticDataBeanList.add(new StaticDataBean(staticData));
        }
        return staticDataBeanList;
    }
}
